/******************************************************
*  Copyright(c) pages.ilovezxl.top
*  FileName : halagent.c
*  Author : rivulet.dave
*  Description : HAL接口文件
*  Data : 2020-06-30
******************************************************/


/*********************************************************************
 * INCLUDES
 */

#include "stdrope.h"
#include "util.h"

#include "hallib.h"
#include "halagent.h"

#include "log.h"
#include "gpio.h"
#include "uart.h"
#include "adc.h"
#include "can.h"
#include "flash.h"
#include "i2c.h"
#include "rtc.h"
#include "spi.h"
#include "timer.h"
#include "wdg.h"

/*********************************************************************
 *  EXTERNAL VARIABLES
 */

/*********************************************************************
 * MACROS
 */

#define MOD_NAME "HAL"

/*********************************************************************
 * TYPES
 */

struct hal_module_cb
{   
    hd_t hThisModule;  // 模块描述符
    hwModId_t enModuleId;
    const char *pModuleName;
    const hal_init_fxn_t pfInitEntry;
    const hal_exit_fxn_t pfExitEntry;
};

/*********************************************************************
 * FUNCTIONS DECLARE
 */

/*********************************************************************
 * VARIABLES
 */

static struct hal_module_cb s_astHalModuleTbl[] =
{
#if (HAL_GPIO == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_GPIO,
        .pModuleName = TOSTR(HW_GPIO),
        .pfInitEntry = GPIO_Init,
        .pfExitEntry = GPIO_Exit
    },
#endif

#if (HAL_UART == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_UART,
        .pModuleName = TOSTR(HW_UART),
        .pfInitEntry = UART_Init,
        .pfExitEntry = UART_Exit
    },
#endif

#if (HAL_ADC == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_ADC,
        .pModuleName = TOSTR(HW_ADC),
        .pfInitEntry = ADC_Init,
        .pfExitEntry = ADC_Exit
    },
#endif

#if (HAL_CAN == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_CAN,
        .pModuleName = TOSTR(HW_CAN),
        .pfInitEntry = CAN_Init,
        .pfExitEntry = CAN_Exit
    },
#endif

#if (HAL_FLASH == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_FLASH,
        .pModuleName = TOSTR(HW_FLASH),
        .pfInitEntry = FLA_Init,
        .pfExitEntry = FLA_Exit
    },
#endif

#if (HAL_I2C == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_I2C,
        .pModuleName = TOSTR(HW_I2C),
        .pfInitEntry = I2C_Init,
        .pfExitEntry = I2C_Exit
    },
#endif

#if (HAL_RTC == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_RTC,
        .pModuleName = TOSTR(HW_RTC),
        .pfInitEntry = RTC_Init,
        .pfExitEntry = RTC_Exit
    },
#endif

#if (HAL_SPI == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_SPI,
        .pModuleName = TOSTR(HW_SPI),
        .pfInitEntry = SPI_Init,
        .pfExitEntry = SPI_Exit
    },
#endif

#if (HAL_TMR == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_TMR,
        .pModuleName = TOSTR(HW_TMR),
        .pfInitEntry = TMR_Init,
        .pfExitEntry = TMR_Exit
    },
#endif

#if (HAL_WDG == _ENABLE)
    {
        .hThisModule = NULL,
        .enModuleId  = HW_WDG,
        .pModuleName = TOSTR(HW_WDG),
        .pfInitEntry = WDG_Init,
        .pfExitEntry = WDG_Exit
    },
#endif
};

/*********************************************************************
 * FUNCTIONS
 */

/**
 *   @Description: HAL层模块安装
 *   @param : NA
 *   @return : _OK/_ERR
 */
int32_t HAL_Install(void)
{
    uint32_t uiModuleNum = _ARRAY_SIZE(s_astHalModuleTbl);

    for (uint32_t i = 0; i < uiModuleNum; i++)
    {
        if (s_astHalModuleTbl[i].pfInitEntry)
        {
            s_astHalModuleTbl[i].hThisModule = s_astHalModuleTbl[i].pfInitEntry();
            if (!s_astHalModuleTbl[i].hThisModule)
            {
                // module init fault
                LOG_ERR(MOD_NAME, "hal module:%s init fail.\n", s_astHalModuleTbl[i].pModuleName);
            }
        }
    }

    return _OK;
}

/**
 *   @Description: HAL层模块卸载
 *   @param : NA
 *   @return:_OK/_ERR
 */
int32_t HAL_Uninstall(void)
{
    uint32_t uiModuleNum = _ARRAY_SIZE(s_astHalModuleTbl);

    for (uint32_t i = 0; i < uiModuleNum; i++)
    {
        if (s_astHalModuleTbl[i].pfExitEntry)
        {
            s_astHalModuleTbl[i].pfExitEntry();
            s_astHalModuleTbl[i].hThisModule = NULL;
        }
    }

    return _OK;
}

/**
 *   @Description: 打开HAL层模块
 *   @param : enModId - 入参，模块ID
 *   @param : uiIdx - 入参，模块索引
 *   @return:模块描述符，0为无效
 */
hd_t HAL_Open(hwModId_t enModId, uint32_t uiIdx)
{
    HAL_OPER_S *pstHalOperation = NULL;

    // 查找相应的模块
    for (uint32_t i = 0; i < _ARRAY_SIZE(s_astHalModuleTbl); i++)
    {
        if (enModId == s_astHalModuleTbl[i].enModuleId)
        {
            pstHalOperation = (HAL_OPER_S *)s_astHalModuleTbl[i].hThisModule;
            break;
        }
    }

    // No Found
    if (!pstHalOperation)
    {
        LOG_ERR(MOD_NAME, "open fail, no found mod:%d.\n", enModId);
        return 0;
    }

    // No Support
    if (!pstHalOperation->pfOpen)
    {
        LOG_ERR(MOD_NAME, "open is null, mod:%d.\n", enModId);
        return 0;
    }
    return pstHalOperation->pfOpen(uiIdx);
}

/**
 *   @Description: 关闭HAL层模块
 *   @param : hModuleDescriptor - 模块描述符
 *   @return:_OK/_ERR
 */
int32_t HAL_Close(hd_t hModuleDescriptor)
{
    HAL_OPER_S *pstHalOperation = (HAL_OPER_S *)hModuleDescriptor;
    
    // Invalid
    if (!pstHalOperation)
    {
        return _ERR;
    }

    // No Support
    if (!pstHalOperation->pfClose)
    {
        return _OK;
    }
    return pstHalOperation->pfClose(pstHalOperation->pThis);
}

/**
 *   @Description: 锁定HAL层模块
 *   @param : hModuleDescriptor - 模块描述符
 *   @param : uiFlag - 特殊标记
 *   @return:_OK/_ERR
 */
int32_t HAL_Lock(hd_t hModuleDescriptor, uint32_t uiFlag)
{
    HAL_OPER_S *pstHalOperation = (HAL_OPER_S *)hModuleDescriptor;
    
    // Invalid
    if (!pstHalOperation)
    {
        return _ERR;
    }

    // No Support
    if (!pstHalOperation->pfLock)
    {
        return _OK;
    }
    return pstHalOperation->pfLock(pstHalOperation->pThis, uiFlag);
}

/**
 *   @Description: 解锁HAL层模块
 *   @param : hModuleDescriptor - 模块描述符
 *   @param : uiFlag - 特殊标记
 *   @return:_OK/_ERR
 */
int32_t HAL_Unlock(hd_t hModuleDescriptor, uint32_t uiFlag)
{
    HAL_OPER_S *pstHalOperation = (HAL_OPER_S *)hModuleDescriptor;
    
    // Invalid
    if (!pstHalOperation)
    {
        return _ERR;
    }

    // No Support
    if (!pstHalOperation->pfUnlock)
    {
        return _OK;
    }
    return pstHalOperation->pfUnlock(pstHalOperation->pThis, uiFlag);
}

/**
 *   @Description: 读取HAL层模块数据
 *   @param : hModuleDescriptor - 模块描述符
 *   @param : pUserBuf - 数据缓存
 *   @param : uiSize - 缓存大小
 *   @param : uiFlag - 特殊标记
 *   @return:_OK/_ERR 读取的数据长度
 */
int32_t HAL_Read(hd_t hModuleDescriptor, uint8_t *pUserBuf, uint32_t uiSize, uint32_t uiFlag)
{
    HAL_OPER_S *pstHalOperation = (HAL_OPER_S *)hModuleDescriptor;
    
    // Invalid
    if (!pstHalOperation)
    {
        return _ERR;
    }

    // No Support
    if (!pstHalOperation->pfRead)
    {
        return _OK;
    }
    return pstHalOperation->pfRead(pstHalOperation->pThis, pUserBuf, uiSize, uiFlag);
}

/**
 *   @Description: 写入HAL层模块数据
 *   @param : hModuleDescriptor - 模块描述符
 *   @param : pUserData - 要写入的数据
 *   @param : uiSize - 要写入的数据长度
 *   @param : uiFlag - 特殊标记
 *   @return:_OK/_ERR 写入的数据长度
 */
int32_t HAL_Write(hd_t hModuleDescriptor, const uint8_t *pUserData, uint32_t uiSize, uint32_t uiFlag)
{
    HAL_OPER_S *pstHalOperation = (HAL_OPER_S *)hModuleDescriptor;
    
    // Invalid
    if (!pstHalOperation)
    {
        return _ERR;
    }

    // No Support
    if (!pstHalOperation->pfWrite)
    {
        return _OK;
    }
    return pstHalOperation->pfWrite(pstHalOperation->pThis, pUserData, uiSize, uiFlag);
}

/**
 *   @Description: 一次性读取HAL层模块数据，不需要Open、Close操作
 *   @param : enModId - 模块ID
 *   @param : uiIdx - 模块内部索引
 *   @param : pUserBuf - 数据缓存
 *   @param : uiSize - 缓存大小
 *   @param : uiFlag - 标记
 *   @return:_OK/_ERR 读取的数据长度
 */
int32_t HAL_ReadOnce(hwModId_t enModId, uint32_t uiIdx, uint8_t *pUserBuf, uint32_t uiSize, uint32_t uiFlag)
{
    HAL_OPER_S *pstHalOperation = NULL;

    // 查找相应的模块
    for (uint32_t i = 0; i < _ARRAY_SIZE(s_astHalModuleTbl); i++)
    {
        if (enModId == s_astHalModuleTbl[i].enModuleId)
        {
            pstHalOperation = (HAL_OPER_S *)s_astHalModuleTbl[i].hThisModule;
            break;
        }
    }

    // No Found
    if (!pstHalOperation)
    {
        return _ERR;
    }    

    // No Support
    if (!pstHalOperation->pfReadOnce)
    {
        return _OK;
    }
    return pstHalOperation->pfReadOnce(uiIdx, pUserBuf, uiSize, uiFlag);
}

/**
 *   @Description: 一次性写入HAL层模块数据，不需要Open、Close操作
 *   @param : enModId - 模块ID
 *   @param : uiIdx - 模块内部索引
 *   @param : pUserData - 要写入的数据
 *   @param : uiSize - 要写入的数据长度
 *   @param : uiFlag - 标记
 *   @return:_OK/_ERR 写入的数据长度
 */
int32_t HAL_WriteOnce(hwModId_t enModId, uint32_t uiIdx, const uint8_t *pUserData, uint32_t uiSize, uint32_t uiFlag)
{
    HAL_OPER_S *pstHalOperation = NULL;

    // 查找相应的模块
    for (uint32_t i = 0; i < _ARRAY_SIZE(s_astHalModuleTbl); i++)
    {
        if (enModId == s_astHalModuleTbl[i].enModuleId)
        {
            pstHalOperation = (HAL_OPER_S *)s_astHalModuleTbl[i].hThisModule;
            break;
        }
    }

    // No Found
    if (!pstHalOperation)
    {
        return _ERR;
    }

    // No Support
    if (!pstHalOperation->pfWriteOnce)
    {
        return _OK;
    }
    return pstHalOperation->pfWriteOnce(uiIdx, pUserData, uiSize, uiFlag);
}

/**
 *   @Description: HAL层模块参数控制
 *   @param : hModuleDescriptor - 模块描述符
 *   @param : uiCmdKey - 命令关键字
 *   @param : pValue - 数据
 *   @return:_OK/_ERR
 */
int32_t HAL_Ctrl(hd_t hModuleDescriptor, uint32_t uiCmdKey, void *pValue)
{
    HAL_OPER_S *pstHalOperation = (HAL_OPER_S *)hModuleDescriptor;
    
    // Invalid
    if (!pstHalOperation)
    {
        return _ERR;
    }

    // No Support
    if (!pstHalOperation->pfCtrl)
    {
        return _OK;
    }
    return pstHalOperation->pfCtrl(pstHalOperation->pThis, uiCmdKey, pValue);
}

/************************************** The End Of File **************************************/

